package model.cubos;

import java.util.Arrays;

import model.strategys.MyStrategys;

/**
 * Esta classe reprenta o {@link CuboMagico} mais conhecido, o 3x3x3. 
 * 
 * @author Joeffison Silvério de Andrade, 21011853, joeffisonsa@gmail.com
 * @version 1.0
 * @since 11/11/11 09:20
 */
public class CuboMagico3x3x3 implements CuboMagico {
	
	protected Adesivo[][][] cubo;
	protected MyStrategys strategy;
	
	public CuboMagico3x3x3(MyStrategys strategy) {
		this.strategy = strategy;
		this.cubo = criaCubo3x3x3(6, 3);
	}
	
	protected Adesivo[][][] criaCubo3x3x3(int n_cores, int dimensao) {
		Adesivo[][][] cube = new Adesivo[6][3][3];
		int count = 0;
		for (int i = 0; i<n_cores; i++) {
			for (int j = 0; j<dimensao; j++) {
				for (int k = 0; k < dimensao; k++) {
					cube[i][j][k] = new Adesivo(count++, Adesivo.getCores()[i]);
				}
			}
		}
/*		{
		 {  Primeira cor.
		    Cada número da matriz mais interna, representa uma peça. 
		  {0, 1, 2},  Primeira linha do cubo, para esta cor. 
		  {3, 4, 5},  Segunda linha do cubo, para esta cor. 
		  {6, 7, 8}   Terceira linha do cubo, para esta cor. 
		   Olhando na vertical, vemos as colunas do cubo. 
		 },
		 {  Segunda cor. 
		  {9, 10, 11},
		  {12, 13, 14},
		  {15, 16, 17}
		 },
		 {  Terceira cor. 
		  {18, 19, 20},
		  {21, 22, 23},
		  {24, 25, 26}
		 },
		 {  Quarta cor. 
		  {27, 28, 29},
		  {30, 31, 32},
		  {33, 34, 35}
		 },
		 {  Quinta cor. 
		  {36, 37, 38},
		  {39, 40, 41},
		  {42, 43, 44}
		 },
		 {  Sexta cor. 
		  {45, 46, 47},
		  {48, 49, 50},
		  {51, 52, 53}
		 }
		};
*/
		return cube;
	}
	
	@Override
	public Adesivo[][][] getCubo() {
		return this.cubo;
	}
	
	@Override
	public void resolver() {
		this.strategy.resolver(this);
	}
	
	@Override
	public String toString() {
		StringBuffer espacos = new StringBuffer(); // organizar o cubo
		for (int i = 0; i < Arrays.toString(cubo[0][0]).length(); i++) { espacos.append(" "); }
		
		StringBuffer str = new StringBuffer();
		for (int j = 0; j<cubo[0].length; j++) {
			str.append(espacos);
			str.append(Arrays.toString(cubo[4][j]));
			str.append("\n");
		}
		int [] interacao_j = {3, 0, 1, 2};
		for (int i = 0; i<cubo[0].length; i++) {
			for (int j : interacao_j) {
				str.append(Arrays.toString(cubo[j][i]));
			}
			str.append("\n");
		}
		for (int j = 0; j<cubo[0].length; j++) {
			str.append(espacos);
			str.append(Arrays.toString(cubo[5][j]));
			str.append("\n");
		}
		
		return str.toString();
	}
	
	@Override
	public void setToStringToColor() {
		for (int i = 0; i<6; i++) {
			for (int j = 0; j<3; j++) {
				for (Adesivo ads : this.cubo[i][j]) {
					ads.setToStringToColor();
				}
			}
		}
	}
	
	@Override
	public void setToStringToNumbers() {
		for (int i = 0; i<6; i++) {
			for (int j = 0; j<3; j++) {
				for (Adesivo ads : this.cubo[i][j]) {
					ads.setToStringToNumbers();
				}
			}
		}
	}
	
	/**
	 *  Pesquisa uma peca no cubo a partir da chave passada. A primeira posicao do array representa a face, o segundo array representa a linha e o terceiro a coluna.
	 * @author Pedro, 21011107, pedro.falcao.ufcg@gmail.com 
	 * @param key A chave da peca a ser procurada.
	 * @return Um array de inteiros representando a posicao da peca com a chave dada.
	 */
	public int[] searchPiece(int key) {
		for (int i = 0; i < cubo.length; i++) {
			for (int j = 0; j < cubo[i].length; j++) {
				for (int k = 0; k < cubo[i][j].length; k++) {
					if (cubo[i][j][k].getKey() == key) {
						return new int[]{i,j,k};
					}
				}
			}
		} return null;
	}
	
	/**
	 * Metodo que calcula a posicao correta da peca passada como parametro a partir da posicao da peca central da mesma cor.
	 * @author Pedro, 21011107, pedro.falcao.ufcg@gmail.com
	 * @param central A peca central da mesma cor.
	 * @param aCalcular A peca cuja posicao sera calculada.
	 * @return Um array de inteiros contendo a posicao correta da peca no cubo na forma [face, linha, coluna] 
	 * @throws Exception Caso o numero da face seja invalido, apenas para evitar erros de semantica.
	 */
	public int[] calculaPosicaoCorreta(Adesivo central, Adesivo aCalcular) throws Exception {
		int indiceDeDistancia = central.getKey() - aCalcular.getKey();
		int[] retorno = this.searchPiece(central.getKey());
		retorno[2] += indiceDeDistancia;
		while (retorno[2] < -3 || retorno[2] > 3) {
			if (retorno[2] < -3) {
				retorno[1]++;
				retorno[2] += 3;
			} else {
				retorno[1]--;
				retorno[2] -= 3;
			}
		}
		while (retorno[1] < -3 || retorno[1] > 3) {
			if (retorno[1] < -3) {
				retorno[0]++;
				retorno[1] += 3;
			} else {
				retorno[0]--;
				retorno[1] -= 3;
			}
		} if (retorno[0] > 6 || retorno[0] < 0) {
			throw new Exception("Erro de semantica!");
		} return retorno;
		
	}
	
	public MyStrategys getStrategy() {
		return strategy;
	}
	
}
